home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / picklist / picklist.pas < prev    next >
Pascal/Delphi Source File  |  1995-12-22  |  9KB  |  353 lines

  1. unit Picklist;
  2.  
  3. {Copyright 1995 by Robert Fabiszak
  4.   Free unrestricted use granted provided this copyright notice
  5.   is maintained.
  6.  
  7.   PICKLIST is an enhanced list box control for Borland's Delphi
  8.   product. Version 1.0. June, 1995}
  9.  
  10. interface
  11.  
  12. uses
  13.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  14.   Forms, Dialogs, StdCtrls, menus;
  15.  
  16. type
  17.  
  18.   TSelectedStyle = (psStandard, psCheckbox, psBoldText, psOwnerDraw);
  19.   PTabArray = ^TTabArray;
  20.   TTabArray = array[0..0] of integer;
  21.  
  22.   EInvalidTabStop = exception;
  23.  
  24.   TPickList = class(TCustomListBox)
  25.   private
  26.     { Private declarations }
  27.     FUseTabs: boolean;
  28.     FSelectedStyle: TSelectedStyle;
  29.     FOnChange : TNotifyEvent;
  30.     FLastSel : integer;
  31.     FTabStops: TStrings;
  32.     procedure Click; override;
  33.   protected
  34.     { Protected declarations }
  35.     procedure SetUseTabStops(bUseTabs: boolean);
  36.     procedure SetSelectedStyle(AStyle: TSelectedStyle);
  37.     procedure CreateParams(var Params: TCreateParams); override;
  38.     procedure Change; virtual;
  39.     procedure DrawCheckboxStyle(Index: integer; Rect: TRect;
  40.       State: TOwnerDrawState);
  41.     procedure DrawBoldStyle(Index: integer; Rect: TRect;
  42.       State: TOwnerDrawState);
  43.     function GetTabStops: string;
  44.     procedure SetTabStops(sTabStops: string);
  45.   public
  46.     { Public declarations }
  47.     constructor Create(AOwner: TComponent); override;
  48.     destructor Destroy;
  49.     procedure SelectAll;
  50.     procedure ClearSelection;
  51.     procedure DrawItem(Index: integer; Rect: TRect; State: TOwnerDrawState);
  52.       override;
  53.   published
  54.     { Published declarations }
  55.     property Align;
  56.     property BorderStyle;
  57.     property Color;
  58.     property Columns;
  59.     property Ctl3D;
  60.     property DragCursor;
  61.     property DragMode;
  62.     property Enabled;
  63.     property ExtendedSelect;
  64.     property Font;
  65.     property IntegralHeight;
  66.     property ItemHeight;
  67.     property Items;
  68.     property MultiSelect;
  69.     property ParentColor;
  70.     property ParentCtl3D;
  71.     property ParentFont;
  72.     property ParentShowHint;
  73.     property PopupMenu;
  74.     property ShowHint;
  75.     property Sorted;
  76.     property TabOrder;
  77.     property TabStop;
  78.     property Visible;
  79.     property OnClick;
  80.     property OnDblClick;
  81.     property OnDragDrop;
  82.     property OnDragOver;
  83.     property OnDrawItem;
  84.     property OnEndDrag;
  85.     property OnEnter;
  86.     property OnExit;
  87.     property OnKeyDown;
  88.     property OnKeyPress;
  89.     property OnKeyUp;
  90.     property OnMeasureItem;
  91.     property OnMouseDown;
  92.     property OnMouseMove;
  93.     property OnMouseUp;
  94.     {custom extensions}
  95.     property UseTabStops: boolean read FUseTabs write SetUseTabStops
  96.       default True;
  97.     property SelectedStyle: TSelectedStyle read FSelectedStyle
  98.       write SetSelectedStyle default psCheckbox;
  99.     {NOTE: TabStops property measured in terms of average character widths}
  100.     property TabStops: string read GetTabStops write SetTabStops;
  101.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  102.   end;
  103.  
  104. procedure Register;
  105.  
  106. implementation
  107.  
  108. constructor TPickList.Create(AOwner: TComponent);
  109. begin
  110.   inherited Create(AOwner);
  111.   Style := lbOwnerDrawFixed;
  112.   FLastSel := -1;
  113.   FUseTabs := True;
  114.   FSelectedStyle := psCheckbox;
  115.   FTabStops := TStringList.Create;
  116. end;
  117.  
  118.  
  119. destructor TPickList.Destroy;
  120. begin
  121.   FTabStops.Free;
  122. end;
  123.  
  124. procedure TPickList.SetUseTabStops(bUseTabs: boolean);
  125. begin
  126.   if FUseTabs <> bUseTabs then
  127.   begin
  128.     FUseTabs := bUseTabs;
  129.     Invalidate
  130.   end;
  131. end;
  132.  
  133.  
  134. procedure TPickList.SetSelectedStyle(AStyle: TSelectedStyle);
  135. begin
  136.   if FSelectedStyle <> AStyle then
  137.   begin
  138.     FSelectedStyle := AStyle;
  139.     if AStyle = psStandard then
  140.       Style := lbStandard
  141.     else
  142.       Style := lbOwnerDrawFixed;
  143.     Invalidate;
  144.   end;
  145. end;
  146.  
  147. procedure TPickList.Change;
  148. begin
  149.   FLastSel := ItemIndex;
  150.   if assigned(FOnChange) then FOnChange(self);
  151. end;
  152.  
  153. procedure TPickList.Click;
  154. begin
  155.   inherited Click;
  156.   if FLastSel <> ItemIndex then
  157.      Change;
  158. end;
  159.  
  160.  
  161. procedure TPickList.CreateParams(var Params: TCreateParams);
  162. begin
  163.   inherited CreateParams(Params);
  164.   if FUseTabs then
  165.     with Params do Style := Style or LBS_USETABSTOPS;
  166. end;
  167.  
  168.  
  169. procedure TPickList.SelectAll;
  170. begin
  171.   if MultiSelect or ExtendedSelect then
  172.     SendMessage(Handle, LB_SETSEL, 1, -1);
  173. end;
  174.  
  175. procedure TPickList.ClearSelection;
  176. begin
  177.   if MultiSelect or ExtendedSelect then
  178.     SendMessage(Handle, LB_SETSEL, 0, -1);
  179. end;
  180.  
  181.  
  182. procedure TPickList.DrawItem(Index: integer; Rect: TRect; State:
  183.   TOwnerDrawState);
  184. begin
  185.   case FSelectedStyle of
  186.     psCheckbox: DrawCheckboxStyle(Index, Rect, State);
  187.     psBoldText: DrawBoldStyle(Index, Rect, State);
  188.     psStandard, psOwnerDraw: inherited DrawItem(Index, Rect, State);
  189.   end;
  190. end;
  191.  
  192.  
  193. procedure TPickList.DrawCheckboxStyle(Index: integer; Rect: TRect;
  194.   State: TOwnerDrawState);
  195. var
  196.   ch: array[0..255] of char;
  197.   TabArray: PTabArray;
  198.   i: integer;
  199.   nTab: integer;
  200.   Metrics: TTextMetric;
  201. begin
  202.   GetTextMetrics(Canvas.Handle, Metrics);
  203.   GetMem(TabArray, FTabStops.Count * sizeof(integer));
  204.   try
  205.     for i := 0 to FTabStops.Count - 1 do
  206.     begin
  207.       try
  208.         nTab := StrToInt(FTabStops[i]);  {if any non-integers, we'll raise exception}
  209.       except
  210.         on EConvertError do
  211.           raise EInvalidTabStop.Create(FTabStops[i] + ' is an invalid tab stop');
  212.       end;
  213.       {convert tab stops from avg. character widths to device units}
  214.       TabArray^[i] := nTab * Metrics.tmAveCharWidth;
  215.     end;
  216.  
  217.     with Canvas do
  218.     begin
  219.       Brush.Color := Color;
  220.       FillRect(Rect);
  221.       {manually set these colors to override the color change when
  222.       the item is focused}
  223.       Font.Color := self.Font.Color;
  224.       Pen.Color := self.Font.Color;
  225.       Rectangle(Rect.Left + 2, Rect.Top + 1, Rect.Left + ItemHeight,
  226.         Rect.Top + ItemHeight - 1);
  227.       if odSelected in State then
  228.       begin
  229.         MoveTo(Rect.Left + 2, Rect.Top + 1);
  230.         LineTo(Rect.Left + ItemHeight, Rect.Top + ItemHeight - 1);
  231.         MoveTo(Rect.Left + ItemHeight - 1, Rect.Top + 1);
  232.         LineTo(Rect.Left + 1, Rect.Top + ItemHeight - 1);
  233.       end;
  234.       if FUseTabs then
  235.         TabbedTextOut(Handle, Rect.Left + ItemHeight + 4, Rect.Top,
  236.           StrPCopy(ch, Items[Index]), Length(Items[Index]), FTabStops.Count,
  237.           TabArray^, 0)
  238.       else
  239.         TextOut(Rect.Left + ItemHeight + 4, Rect.Top, Items[Index]);
  240.     end;
  241.   finally
  242.     FreeMem(TabArray, FTabStops.Count * sizeof(integer));
  243.   end;
  244. end;
  245.  
  246.  
  247. procedure TPickList.DrawBoldStyle(Index: integer; Rect: TRect;
  248.   State: TOwnerDrawState);
  249. var
  250.   ch: array[0..255] of char;
  251.   TabArray: PTabArray;
  252.   i: integer;
  253.   Metrics: TTextMetric;
  254.   nTab: integer;
  255. begin
  256.   GetTextMetrics(Canvas.Handle, Metrics);
  257.   GetMem(TabArray, FTabStops.Count * sizeof(integer));
  258.   try
  259.     for i := 0 to FTabStops.Count - 1 do
  260.     begin
  261.       try
  262.         nTab := StrToInt(FTabStops[i]);  {if any non-integers, we'll raise exception}
  263.       except
  264.         on EConvertError do
  265.           raise EInvalidTabStop.Create(FTabStops[i] + ' is an invalid tab stop');
  266.       end;
  267.       {convert tab stops from avg. character widths to device units}
  268.       TabArray^[i] := nTab * Metrics.tmAveCharWidth;
  269.     end;
  270.  
  271.     with Canvas do
  272.     begin
  273.       Brush.Color := Color;
  274.       FillRect(Rect);
  275.       {manually set these colors to override the color change when
  276.       the item is focused}
  277.       Font.Color := self.Font.Color;
  278.       Pen.Color := self.Font.Color;
  279.       if odSelected in State then
  280.         Font.Style := Font.Style + [fsBold]
  281.       else
  282.         Font.Style := Font.Style - [fsBold];
  283.       if FUseTabs then
  284.         TabbedTextOut(Handle, Rect.Left + 2, Rect.Top, StrPCopy(ch, Items[Index]),
  285.           Length(Items[Index]), FTabStops.Count, TabArray^, 0)
  286.       else
  287.         TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
  288.     end;
  289.   finally
  290.     FreeMem(TabArray, FTabStops.Count * sizeof(integer));
  291.   end;
  292. end;
  293.  
  294.  
  295. function TPickList.GetTabStops: string;
  296. var
  297.   i: integer;
  298. begin
  299.   Result := '';
  300.   for i := 0 to FTabStops.Count - 1 do
  301.   begin
  302.     Result := Result + FTabStops[i];
  303.     if i < FTabStops.Count - 1 then
  304.       Result := Result + ';';
  305.   end;
  306. end;
  307.  
  308.  
  309. procedure TPickList.SetTabStops(sTabStops: string);
  310. var
  311.   sTemp: string;
  312.   i: integer;
  313.   nTab: integer;
  314. begin
  315.   FTabStops.Clear;     {get rid of current tab stops}
  316.   if Length(sTabStops) = 0 then
  317.     Exit;             {we're clearing the tab stops}
  318.   sTemp := '';
  319.   for i := 1 to Length(sTabStops) do
  320.   begin
  321.     if (sTabStops[i] = ';') and (i > 1) then
  322.     begin
  323.       try
  324.         nTab := StrToInt(sTemp);  {if any non-integers, we'll raise exception}
  325.       except
  326.         on EConvertError do
  327.           raise EInvalidTabStop.Create(sTemp + ' is an invalid tab stop');
  328.       end;
  329.       FTabStops.Add(sTemp);
  330.       sTemp := '';
  331.     end
  332.     else
  333.       sTemp := sTemp + sTabStops[i];
  334.   end;
  335.   {now make sure we add the final token}
  336.   try
  337.     nTab := StrToInt(sTemp);  {if any non-integers, we'll raise exception}
  338.   except
  339.     on EConvertError do
  340.       raise EInvalidTabStop.Create(sTemp + ' is an invalid tab stop');
  341.   end;
  342.   FTabStops.Add(sTemp);
  343.   Invalidate;
  344. end;
  345.  
  346.  
  347. procedure Register;
  348. begin
  349.   RegisterComponents('Extensions', [TPickList]);
  350. end;
  351.  
  352. end.
  353.